// Flo-Memory vector
// $Id: big_vector.h 516 2010-07-16 17:43:00Z Oleg.Bulychov $
#pragma once

#include "src/heo/include/alloc_big.h"

/** NOTE:
T can be a class, but must not call big_allocator*
*/
template<typename T>
class big_vector_base
{
    typedef mem_util::TFloHeader* PFloHeader;
    DISALLOW_COPY_AND_ASSIGN(big_vector_base);
protected:
    T** pp_;
public:
    typedef T value_type;
//.............................................................................
    explicit big_vector_base(size_t capacity = 0) NO_THROW_():
        pp_(big_allocator::AllocT<T>(0, capacity))
    {}
//.............................................................................
    ~big_vector_base() NO_THROW_()
    {
        big_allocator::FreeT(pp_);
    }
//.............................................................................
    size_t size() const NO_THROW_()
    {
        return PFloHeader(*pp_)[-1].data_size_ / sizeof(T);
    }
//.............................................................................
    //:hint - so can be zero
    size_t reserved() const NO_THROW_()
    {
        return (PFloHeader(*pp_)[-1].block_size_) / sizeof(T);
    }
//.............................................................................
    bool is_Empty() const NO_THROW_()
    {
        return !size();
    }
//.............................................................................
    bool bad_Index(size_t index) const NO_THROW_()
    { 
        return index >= size();
    }
//.............................................................................
    T& operator[](size_t i) NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return (*pp_)[i];
    }
//.............................................................................
    T const& operator[](size_t i) const NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return (*pp_)[i];
    }
//.............................................................................
    T& get(size_t i) NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return (*pp_)[i];
    }
//.............................................................................
    T const& get(size_t i) const NO_THROW_()
    {
        ASSERT_(!bad_Index(i));
        return (*pp_)[i];
    }
//.............................................................................
    T& front() NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return **pp_;
    }
//.............................................................................
    T const& front() const NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return **pp_;
    }
//.............................................................................
    T& back() NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return get(size() - 1);
    }
//.............................................................................
    T const& back() const NO_THROW_()
    {
        ASSERT_(!is_Empty());
        return get(size() - 1);
    }
//.............................................................................
    T* begin() NO_THROW_()
    {
        return *pp_;
    }
//.............................................................................
    T const* begin() const NO_THROW_()
    {
        return *pp_;
    }
//.............................................................................
    T* end() NO_THROW_()
    {
        return &(*pp_)[size()];
    }
//.............................................................................
    T const* end() const NO_THROW_()
    {
        return &(*pp_)[size()];
    }
//.............................................................................
    T** get_Buffer() NO_THROW_() { return pp_; }
//.............................................................................
    void swap(big_vector_base<T>& right) NO_THROW_()
    {
        std::swap(pp_, right.pp_);
    }
//.............................................................................
    template<typename U>
    void push_back(U const& item)
    {
        size_t old_size = size();
        resize_Up(old_size + 1);
        new(&(*pp_)[old_size]) T(item);
    }
//.............................................................................
    template<typename U>
    void insert(size_t at, U const& item)
    {
        size_t old_size = size();
        ASSERT_(at <= old_size);
        resize_Up(old_size + 1);
        memmove(*pp_ + at + 1, *pp_ + at, sizeof(T) * (old_size - at));
        new(&(*pp_)[at]) T(item);
    }
//.............................................................................
//.............................................................................
//.............................................................................
    void resize(size_t new_size, size_t new_reserved = 0) NO_THROW_()
    {
        big_allocator::ReallocT(*pp_, new_size, new_reserved);
    }
//.............................................................................
    void resize_Up(size_t new_size) NO_THROW_()
    {
        size_t new_reserved = reserved();
        if (!new_reserved)
            new_reserved = new_size + new_size / 2;
        big_allocator::ReallocT(*pp_, new_size, new_reserved);
    }
//.............................................................................
    void resize_Down(size_t new_size) NO_THROW_()
    {
        big_allocator::ReallocT(*pp_, new_size, reserved());
    }
//.............................................................................
//.............................................................................
    void destruct_All() NO_THROW_()
    {
        mem_util::Initialized_Destruct(*pp_, *pp_ + size());
    }
//.............................................................................
    void pop_Back() NO_THROW_()
    {
        size_t old_size = size();
        ASSERT_(old_size);
        (*pp_)[old_size - 1].~T();
        resize_Down(old_size - 1);
    }
//.............................................................................
    void erase_(size_t i, size_t count = 1) NO_THROW_()
    {
        size_t old_size = size();
        ASSERT_(i + count <= old_size);
        mem_util::Erase(*pp_ + i, *pp_ + i + count, *pp_ + old_size);
        resize_Down(old_size - count);
    }
//.............................................................................
//.............................................................................
//.............................................................................
};
//__________________________________________________________________________________
//__________________________________________________________________________________
template<typename T>
class big_vector:
    protected big_vector_base<T>
{
    typedef big_vector_base<T> Base_;
protected:
    using Base_::pp_;
public:
    typedef T value_type;
    typedef T& reference;
    typedef T const& const_reference;
    typedef T* pointer;
    typedef T const* const_pointer;
    typedef T* iterator;
    typedef T const* const_iterator;
    typedef size_t size_type;
//.............................................................................
    using Base_::operator[];
    using Base_::get;
    using Base_::size;
    using Base_::reserved;
    using Base_::is_Empty;
    using Base_::bad_Index;
    using Base_::back;
    using Base_::front;
    using Base_::begin;
    using Base_::end;
    using Base_::push_back;
    using Base_::resize;
//.............................................................................
    explicit big_vector(size_t capacity = 0) NO_THROW_(): Base_(capacity)
    {}
//.............................................................................
    ~big_vector() NO_THROW_()
    {
        Base_::destruct_All();
    }
//.............................................................................
    void swap(big_vector<T>& right) NO_THROW_()
    {//:sic: type cast is inaccessible
        Base_::swap(right);
    }
//.............................................................................
    void pop_back() NO_THROW_()
    {
        Base_::pop_Back();
    }
//.............................................................................
};
//__________________________________________________________________________________
template<typename T, class Compare>
class big_sorted_vector:
    protected big_vector_base<T>
{
    typedef big_vector_base<T> Base_;
protected:
    using Base_::pp_;
public:
    typedef T value_type;
    typedef T& reference;
    typedef T const& const_reference;
    typedef size_t size_type;
    typedef T* pointer;
    typedef T const* const_pointer;
    typedef T* iterator;
    typedef T const* const_iterator;
//.............................................................................
    using Base_::operator[];
    using Base_::get;
    using Base_::size;
    using Base_::reserved;
    using Base_::is_Empty;
    using Base_::bad_Index;
    using Base_::back;
    using Base_::front;
    using Base_::begin;
    using Base_::end;
//.............................................................................
    explicit big_sorted_vector(size_t capacity = 0) NO_THROW_(): Base_(capacity)
    {}
//.............................................................................
    ~big_sorted_vector() NO_THROW_()
    {
        Base_::destruct_All();
    }
//.............................................................................
    void swap(big_sorted_vector<T, Compare>& right) NO_THROW_()
    {//:sic: type cast is inaccessible
        Base_::swap(right);
    }
//.............................................................................
    template<typename U>
    void push(U const& item)
    {
        size_t i = std::lower_bound(begin(), end(), item, Compare()) - begin();
        insert(i, item);
    }
//.............................................................................
    T& top() NO_THROW_()
    {
        return back();
    }
//.............................................................................
    T const& top() const NO_THROW_()
    {
        return back();
    }
//.............................................................................
    void pop() NO_THROW_()
    {
        Base_::pop_Back();
    }
//.............................................................................
//.............................................................................
    void erase(size_t i, size_t count = 1) NO_THROW_()
    {
        Base_::erase_(i, count);
    }
//.............................................................................
//.............................................................................
//.............................................................................
//.............................................................................
};
//__________________________________________________________________________________

//EOF!
